home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / netz / term / extras / source / term-source.lha / termARexx.c < prev    next >
C/C++ Source or Header  |  1995-02-07  |  19KB  |  1,056 lines

  1. /*
  2. **    termARexx.c
  3. **
  4. **    ARexx interface general support routines
  5. **
  6. **    Copyright © 1990-1995 by Olaf `Olsen' Barthel
  7. **        All Rights Reserved
  8. */
  9.  
  10. #include "termARexxGlobal.h"
  11.  
  12.     /* IsNumeric(STRPTR String):
  13.      *
  14.      *    Is the string really a number?
  15.      */
  16.  
  17. BYTE __regargs
  18. IsNumeric(STRPTR String)
  19. {
  20.     while(*String && (*String == ' ' || *String == '\t'))
  21.         String++;
  22.  
  23.     while(*String)
  24.     {
  25.         if(*String < '0' || *String > '9')
  26.             return(FALSE);
  27.         else
  28.             String++;
  29.     }
  30.  
  31.     return(TRUE);
  32. }
  33.  
  34.     /* CreateResult(STRPTR ResultString,LONG *Results):
  35.      *
  36.      *    Create a proper Rexx result string.
  37.      */
  38.  
  39. STRPTR __regargs
  40. CreateResult(STRPTR ResultString,LONG *Results)
  41. {
  42.     STRPTR Result;
  43.  
  44.     if(!(Result = CreateArgstring(ResultString,strlen(ResultString))))
  45.     {
  46.         Results[0] = RC_ERROR;
  47.         Results[1] = ERROR_NO_FREE_STORE;
  48.     }
  49.  
  50.     return(Result);
  51. }
  52.  
  53.     /* CreateResultLen(STRPTR ResultString,LONG *Results):
  54.      *
  55.      *    Create a proper Rexx result string given the
  56.      *    length of the source string.
  57.      */
  58.  
  59. STRPTR __regargs
  60. CreateResultLen(STRPTR ResultString,LONG *Results,LONG Len)
  61. {
  62.     STRPTR Result;
  63.  
  64.     if(!(Result = CreateArgstring(ResultString,Len)))
  65.     {
  66.         Results[0] = RC_ERROR;
  67.         Results[1] = ERROR_NO_FREE_STORE;
  68.     }
  69.  
  70.     return(Result);
  71. }
  72.  
  73.     /* CreateVarArgs(STRPTR Value,struct RexxPkt *Packet,STRPTR Stem,...):
  74.      *
  75.      *    Set a Rexx variable, special treatment.
  76.      */
  77.  
  78. BYTE __stdargs
  79. CreateVarArgs(STRPTR Value,struct RexxPkt *Packet,STRPTR Stem,...)
  80. {
  81.     UBYTE    Name[256];
  82.     va_list    VarArgs;
  83.     LONG    Result;
  84.  
  85.     va_start(VarArgs,Stem);
  86.     VSPrintf(Name,Stem,VarArgs);
  87.     va_end(VarArgs);
  88.  
  89.     if(Result = SetRexxVar(Packet -> RexxMsg,Name,Value,strlen(Value)))
  90.     {
  91.         Packet -> Results[0] = RC_ERROR;
  92.         Packet -> Results[1] = Result;
  93.  
  94.         return(FALSE);
  95.     }
  96.     else
  97.         return(TRUE);
  98. }
  99.  
  100.     /* CreateVar(STRPTR Value,struct RexxPkt *Packet,STRPTR Name):
  101.      *
  102.      *    Set a Rexx variable, simple version.
  103.      */
  104.  
  105. STRPTR __regargs
  106. CreateVar(STRPTR Value,struct RexxPkt *Packet,STRPTR Name)
  107. {
  108.     LONG Result;
  109.  
  110.     if(Result = SetRexxVar(Packet -> RexxMsg,Name,Value,strlen(Value)))
  111.     {
  112.         Packet -> Results[0] = RC_ERROR;
  113.         Packet -> Results[1] = Result;
  114.     }
  115.  
  116.     return(NULL);
  117. }
  118.  
  119.     /* CreateMatchBuffer(STRPTR Pattern):
  120.      *
  121.      *    Create a pattern buffer suitable for pattern matching.
  122.      */
  123.  
  124. STRPTR __regargs
  125. CreateMatchBuffer(STRPTR Pattern)
  126. {
  127.     WORD    Len = strlen(Pattern) + 1;
  128.     STRPTR    Buffer;
  129.  
  130.     if(Buffer = (STRPTR)AllocVecPooled(2 * Len,MEMF_ANY))
  131.     {
  132.         if(ParsePatternNoCase(Pattern,Buffer,2 * Len) != -1)
  133.             return(Buffer);
  134.         else
  135.             FreeVecPooled(Buffer);
  136.     }
  137.  
  138.     return(NULL);
  139. }
  140.  
  141.     /* MatchBuffer(STRPTR Buffer,STRPTR Name):
  142.      *
  143.      *    Match a pattern against a string.
  144.      */
  145.  
  146. BYTE __regargs
  147. MatchBuffer(STRPTR Buffer,STRPTR Name)
  148. {
  149.     return((BYTE)MatchPatternNoCase(Buffer,Name));
  150. }
  151.  
  152.     /* DeleteMatchBuffer(STRPTR Buffer):
  153.      *
  154.      *    Free a pattern matching buffer.
  155.      */
  156.  
  157. VOID __regargs
  158. DeleteMatchBuffer(STRPTR Buffer)
  159. {
  160.     FreeVecPooled(Buffer);
  161. }
  162.  
  163.     /* ToMode(STRPTR Name):
  164.      *
  165.      *    Turn a transfer mode name into a key.
  166.      */
  167.  
  168. WORD __regargs
  169. ToMode(STRPTR Name)
  170. {
  171.     STATIC STRPTR TransferModes[] =
  172.     {
  173.         "BINARY",
  174.         "TEXT",
  175.         "ASCII",
  176.         NULL
  177.     };
  178.  
  179.     WORD i;
  180.  
  181.     for(i = 0 ; TransferModes[i] ; i++)
  182.     {
  183.         if(!Stricmp(Name,TransferModes[i]))
  184.             return(i);
  185.     }
  186.  
  187.     return(-1);
  188. }
  189.  
  190.     /* ToList(STRPTR Name):
  191.      *
  192.      *    Turn a list name into a key.
  193.      */
  194.  
  195. WORD __regargs
  196. ToList(STRPTR Name)
  197. {
  198.     STATIC STRPTR ListTypes[GLIST_COUNT] =
  199.     {
  200.         "UPLOAD",
  201.         "DOWNLOAD",
  202.         "DIAL",
  203.         "WAIT",
  204.         "TRAP"
  205.     };
  206.  
  207.     WORD i;
  208.  
  209.     for(i = 0 ; i < GLIST_COUNT ; i++)
  210.     {
  211.         if(!Stricmp(Name,ListTypes[i]))
  212.             return(i);
  213.     }
  214.  
  215.     return(-1);
  216. }
  217.  
  218.     /* ToConfig(STRPTR Name):
  219.      *
  220.      *    Turn a configuration name into a key.
  221.      */
  222.  
  223. WORD __regargs
  224. ToConfig(STRPTR Name)
  225. {
  226.     STATIC STRPTR DataTypes[DATATYPE_COUNT] =
  227.     {
  228.         "TRANSLATIONS",
  229.         "FUNCTIONKEYS",
  230.         "CURSORKEYS",
  231.         "FASTMACROS",
  232.         "HOTKEYS",
  233.         "SPEECH",
  234.         "SOUND",
  235.         "BUFFER",
  236.         "CONFIGURATION",
  237.         "PHONE",
  238.         "SCREENTEXT",
  239.         "SCREENIMAGE"
  240.     };
  241.  
  242.     WORD i;
  243.  
  244.     for(i = 0 ; i < DATATYPE_COUNT ; i++)
  245.     {
  246.         if(!Stricmp(Name,DataTypes[i]))
  247.             return(i);
  248.     }
  249.  
  250.     return(-1);
  251. }
  252.  
  253.     /* ToRequester(STRPTR Name):
  254.      *
  255.      *    Turn a requester name into a key.
  256.      */
  257.  
  258. WORD __regargs
  259. ToRequester(STRPTR Name)
  260. {
  261.     STRPTR RequesterTypes[REQUESTER_COUNT] =
  262.     {
  263.         "SERIAL",
  264.         "MODEM",
  265.         "SCREEN",
  266.         "TERMINAL",
  267.         "EMULATION",
  268.         "CLIPBOARD",
  269.         "CAPTURE",
  270.         "COMMANDS",
  271.         "MISC",
  272.         "PATH",
  273.         "TRANSFER",
  274.         "TRANSLATIONS",
  275.         "FUNCTIONKEYS",
  276.         "CURSORKEYS",
  277.         "FASTMACROS",
  278.         "HOTKEYS",
  279.         "SPEECH",
  280.         "SOUND",
  281.         "PHONE"
  282.     };
  283.  
  284.     WORD i;
  285.  
  286.     for(i = 0 ; i < REQUESTER_COUNT ; i++)
  287.     {
  288.         if(!Stricmp(Name,RequesterTypes[i]))
  289.             return(i);
  290.     }
  291.  
  292.     return(-1);
  293. }
  294.  
  295.     /* ToWindow(STRPTR Name):
  296.      *
  297.      *    Turn a window name into a key.
  298.      */
  299.  
  300. WORD __regargs
  301. ToWindow(STRPTR Name)
  302. {
  303.     STATIC STRPTR WindowTypes[WINDOWID_COUNT] =
  304.     {
  305.         "BUFFER",
  306.         "REVIEW",
  307.         "PACKET",
  308.         "FASTMACROS",
  309.         "STATUS",
  310.         "MAIN",
  311.         "UPLOADQUEUE"
  312.     };
  313.  
  314.     WORD i;
  315.  
  316.     for(i = 0 ; i < WINDOWID_COUNT ; i++)
  317.     {
  318.         if(!Stricmp(WindowTypes[i],Name))
  319.             return(i);
  320.     }
  321.  
  322.     return(-1);
  323. }
  324.  
  325.     /* ReplyRexxCommand():
  326.      *
  327.      *    Reply a command request the rexx server - or someone else -
  328.      *    has passed to us.
  329.      */
  330.  
  331. STATIC VOID __regargs
  332. ReplyRexxCommand(struct RexxMsg *RexxMessage,LONG Primary,LONG Secondary)
  333. {
  334.     if(RexxMessage)
  335.     {
  336.         RexxMessage -> rm_Result1 = Primary;
  337.         RexxMessage -> rm_Result2 = Secondary;
  338.  
  339.         ReplyMsg(RexxMessage);
  340.     }
  341. }
  342.  
  343.     /* RexxToolServer(VOID):
  344.      *
  345.      *    Asynchronous tool/rexx command execution process.
  346.      */
  347.  
  348. STATIC VOID __saveds
  349. RexxToolServer(VOID)
  350. {
  351.     struct Process    *ThisProcess = (struct Process *)SysBase -> ThisTask;
  352.     struct RexxPkt    *Packet;
  353.     BPTR         OldCOS,
  354.              NewCOS    = NULL;
  355.  
  356.         /* Wait for startup packet. */
  357.  
  358.     WaitPort(&ThisProcess -> pr_MsgPort);
  359.  
  360.     Packet = (struct RexxPkt *)GetMsg(&ThisProcess -> pr_MsgPort);
  361.  
  362.         /* Increment usage count. */
  363.  
  364.     ObtainSemaphore(&RexxLaunchSemaphore);
  365.  
  366.     RexxLaunchCount++;
  367.  
  368.     ReleaseSemaphore(&RexxLaunchSemaphore);
  369.  
  370.         /* Create proper output stream if necessary. */
  371.  
  372.     if(!ThisProcess -> pr_COS && ThisProcess -> pr_ConsoleTask)
  373.     {
  374.         if(NewCOS = Open("*",MODE_NEWFILE))
  375.         {
  376.             OldCOS = ThisProcess -> pr_COS;
  377.  
  378.             ThisProcess -> pr_COS = NewCOS;
  379.         }
  380.     }
  381.  
  382.         /* Execute the command. */
  383.  
  384.     (*Packet -> CommandInfo -> Routine)(Packet);
  385.  
  386.     Forbid();
  387.  
  388.         /* Decrement usage count. */
  389.  
  390.     ObtainSemaphore(&RexxLaunchSemaphore);
  391.  
  392.     RexxLaunchCount--;
  393.  
  394.     ReleaseSemaphore(&RexxLaunchSemaphore);
  395.  
  396.         /* Close the output stream. */
  397.  
  398.     if(NewCOS)
  399.     {
  400.         ThisProcess -> pr_COS = OldCOS;
  401.  
  402.         Close(NewCOS);
  403.     }
  404.  
  405.         /* Return the message packet. */
  406.  
  407.     ReplyMsg((struct Message *)Packet);
  408. }
  409.  
  410.     /* InvokeRexxCommand(struct RexxPkt *Packet):
  411.      *
  412.      *    Invoke an ARexx command.
  413.      */
  414.  
  415. STATIC BYTE __regargs
  416. InvokeRexxCommand(struct RexxPkt *Packet)
  417. {
  418.         /* Asynchronous command? */
  419.  
  420.     if(Packet -> CommandInfo -> Async)
  421.     {
  422.             /* Requires special execution code? */
  423.  
  424.         if(Packet -> CommandInfo -> Tool)
  425.         {
  426.             struct RexxPkt *NewPacket;
  427.  
  428.                 /* Create a command packet. */
  429.  
  430.             if(NewPacket = (struct RexxPkt *)AllocVecPooled(sizeof(struct RexxPkt),MEMF_ANY | MEMF_PUBLIC))
  431.             {
  432.                 enum    {    ARG_CONSOLE };
  433.  
  434.                 struct Process    *NewProcess;
  435.                 BPTR         Stream;
  436.  
  437.                     /* Set up the command packet. */
  438.  
  439.                 CopyMem(Packet,NewPacket,sizeof(struct RexxPkt));
  440.  
  441.                 NewPacket -> VanillaMessage . mn_ReplyPort    = RexxPort;
  442.                 NewPacket -> VanillaMessage . mn_Length        = sizeof(struct RexxPkt);
  443.  
  444.                     /* Create I/O streams. */
  445.  
  446.                 if(Packet -> Array[ARG_CONSOLE] && WindowName[0] && Packet -> CommandInfo -> Console)
  447.                     Stream = Open(WindowName,MODE_NEWFILE);
  448.                 else
  449.                     Stream = NULL;
  450.  
  451.                     /* Launch the process. */
  452.  
  453.                 if(Stream && GoodStream(Stream))
  454.                 {
  455.                     struct FileHandle *Handle = (struct FileHandle *)BADDR(Stream);
  456.  
  457.                     NewProcess = CreateNewProcTags(
  458.                         NP_Entry,    RexxToolServer,
  459.                         NP_Input,    Stream,
  460.                         NP_Output,    NULL,
  461.                         NP_ConsoleTask,    Handle -> fh_Type,
  462.                         NP_StackSize,    8000,
  463.                         NP_Name,    "term Rexx Tool Process",
  464.                         NP_Cli,        TRUE,
  465.                     TAG_DONE);
  466.                 }
  467.                 else
  468.                 {
  469.                     NewProcess = CreateNewProcTags(
  470.                         NP_Entry,    RexxToolServer,
  471.                         NP_StackSize,    8000,
  472.                         NP_ConsoleTask,    NULL,
  473.                         NP_Name,    "term Rexx Tool Process",
  474.                         NP_Cli,        TRUE,
  475.                     TAG_DONE);
  476.                 }
  477.  
  478.                     /* Send the command packet. */
  479.  
  480.                 if(NewProcess)
  481.                     PutMsg(&NewProcess -> pr_MsgPort,(struct Message *)NewPacket);
  482.                 else
  483.                 {
  484.                     FreeVecPooled(NewPacket);
  485.  
  486.                     ReplyRexxCommand(Packet -> RexxMsg,-1,0);
  487.  
  488.                     if(Stream)
  489.                         Close(Stream);
  490.                 }
  491.             }
  492.             else
  493.                 ReplyRexxCommand(Packet -> RexxMsg,-1,0);
  494.         }
  495.         else
  496.         {
  497.                 /* Execute the command on the schedule of the
  498.                  * rexx server process.
  499.                  */
  500.  
  501.             STRPTR Result = (*Packet -> CommandInfo -> Routine)(Packet);
  502.  
  503.             RexxPktCleanup(Packet,Result);
  504.         }
  505.     }
  506.     else
  507.     {
  508.         struct RexxPkt *NewPacket;
  509.  
  510.             /* Create message packet. */
  511.  
  512.         if(NewPacket = (struct RexxPkt *)AllocVecPooled(sizeof(struct RexxPkt),MEMF_ANY | MEMF_PUBLIC))
  513.         {
  514.                 /* Set up message packet. */
  515.  
  516.             CopyMem(Packet,NewPacket,sizeof(struct RexxPkt));
  517.  
  518.             NewPacket -> VanillaMessage . mn_ReplyPort    = RexxPort;
  519.             NewPacket -> VanillaMessage . mn_Length        = sizeof(struct RexxPkt);
  520.  
  521.                 /* Post it. */
  522.  
  523.             PutMsg(TermRexxPort,(struct Message *)NewPacket);
  524.         }
  525.         else
  526.             ReplyRexxCommand(Packet -> RexxMsg,-1,0);
  527.     }
  528.  
  529.     return(TRUE);
  530. }
  531.  
  532.     /* ParseRexxCommand(struct RexxMsg *RexxMsg):
  533.      *
  534.      *    Handles the synchronous Rexx commands and returns the
  535.      *    message if no matching command is found.
  536.      */
  537.  
  538. STATIC BYTE __regargs
  539. ParseRexxCommand(struct RexxMsg *RexxMsg)
  540. {
  541.     UBYTE    CommandBuffer[30];
  542.     STRPTR    Command,
  543.         CommandArgs;
  544.     LONG    Len = 0;
  545.  
  546.         /* Clear the local variables. */
  547.  
  548.     CommandBuffer[0]    = 0;
  549.     Command            = RexxMsg -> rm_Args[0];
  550.     CommandArgs        = NULL;
  551.  
  552.         /* Skip leading blank spaces. */
  553.  
  554.     while(*Command && (*Command == ' ' || *Command == '\t'))
  555.         Command++;
  556.  
  557.         /* Extract the command name. */
  558.  
  559.     do
  560.     {
  561.             /* Found the end of the string? */
  562.  
  563.         if(!Command[Len])
  564.         {
  565.                 /* Copy the command name. */
  566.  
  567.             strcpy(CommandBuffer,Command);
  568.  
  569.                 /* No arguments are provided. */
  570.  
  571.             CommandArgs = NULL;
  572.  
  573.             break;
  574.         }
  575.  
  576.             /* Found a blank space? */
  577.  
  578.         if(Command[Len] == ' ' || Command[Len] == '\t')
  579.         {
  580.                 /* Copy the command name. */
  581.  
  582.             memcpy(CommandBuffer,Command,Len);
  583.  
  584.             CommandBuffer[Len] = 0;
  585.  
  586.                 /* Look for any arguments. */
  587.  
  588.             CommandArgs = &Command[Len + 1];
  589.  
  590.                 /* Skip blank spaces. */
  591.  
  592.             while(*CommandArgs && (*CommandArgs == ' ' || *CommandArgs == '\t'))
  593.                 CommandArgs++;
  594.  
  595.             break;
  596.         }
  597.     }
  598.     while(++Len < 30);
  599.  
  600.         /* Did we find a command name? */
  601.  
  602.     if(CommandBuffer[0])
  603.     {
  604.         struct CommandInfo    *CommandInfo = NULL;
  605.         LONG             CommandIndex;
  606.  
  607.             /* Which command is it? */
  608.  
  609.         for(CommandIndex = 0 ; CommandIndex < CommandTableSize ; CommandIndex++)
  610.         {
  611.             if(!Stricmp(CommandBuffer,CommandTable[CommandIndex] . Name))
  612.             {
  613.                 CommandInfo = &CommandTable[CommandIndex];
  614.  
  615.                 break;
  616.             }
  617.         }
  618.  
  619.             /* Did we find the command? */
  620.  
  621.         if(CommandInfo)
  622.         {
  623.             struct RexxPkt __aligned    Packet;
  624.             BYTE                Processed = FALSE;
  625.  
  626.                 /* Set the result codes to defaults. */
  627.  
  628.             Packet . Results[0]    = RC_OK;
  629.             Packet . Results[1]    = 0;
  630.  
  631.                 /* Fill in the rest. */
  632.  
  633.             Packet . CommandInfo    = CommandInfo;
  634.             Packet . RexxMsg    = RexxMsg;
  635.  
  636.                 /* Does this command accept any arguments? */
  637.  
  638.             if(CommandInfo -> Arguments)
  639.             {
  640.                 LONG *Array;
  641.  
  642.                     /* Determine length of argument string. */
  643.  
  644.                 if(CommandArgs)
  645.                     Len = strlen(CommandArgs);
  646.                 else
  647.                     Len = 0;
  648.  
  649.                     /* Allocate temporary buffer, we will need to
  650.                      * attach a line-feed character to the argument
  651.                      * string.
  652.                      */
  653.  
  654.                 if(Array = (LONG *)AllocVecPooled(12 * sizeof(LONG) + Len + 2,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  655.                 {
  656.                     STRPTR         Buffer;
  657.                     struct RDArgs    *Args;
  658.  
  659.                         /* Get the argument buffer. */
  660.  
  661.                     Buffer = (STRPTR)&Array[12];
  662.  
  663.                         /* Copy the argument string. */
  664.  
  665.                     if(CommandArgs && Len)
  666.                         memcpy(Buffer,CommandArgs,Len);
  667.  
  668.                         /* Attach the line-feed character. */
  669.  
  670.                     Buffer[Len] = '\n';
  671.  
  672.                         /* Allocate argument parser data. */
  673.  
  674.                     if(Args = (struct RDArgs *)AllocDosObjectTags(DOS_RDARGS,TAG_DONE))
  675.                     {
  676.                         Packet . Array    = (STRPTR *)Array;
  677.                         Packet . Args    = Args;
  678.  
  679.                             /* Don't prompt for input! */
  680.  
  681.                         Args -> RDA_Flags |= RDAF_NOPROMPT;
  682.  
  683.                             /* Set up parser data. */
  684.  
  685.                         Args -> RDA_Source . CS_Buffer    = Buffer;
  686.                         Args -> RDA_Source . CS_Length    = Len + 1;
  687.                         Args -> RDA_Source . CS_CurChr    = 0;
  688.  
  689.                             /* Parse the arguments. */
  690.  
  691.                         if(ReadArgs(CommandInfo -> Arguments,Array,Args))
  692.                         {
  693.                             UWORD    Inclusion    = InclusionTable[CommandIndex];
  694.                             BYTE    ArgsRequired    = FALSE;
  695.                             WORD    i,Counted;
  696.  
  697.                                 /* Look for required arguments. */
  698.  
  699.                             for(i = Counted = 0 ; i < 12 ; i++)
  700.                             {
  701.                                 if(Inclusion & (1L << i))
  702.                                 {
  703.                                     ArgsRequired = TRUE;
  704.  
  705.                                     if(Array[i])
  706.                                         Counted++;
  707.                                 }
  708.                             }
  709.  
  710.                                 /* Are any arguments required
  711.                                  * but not provided?
  712.                                  */
  713.  
  714.                             if(ArgsRequired && !Counted)
  715.                             {
  716.                                 Packet . Results[0] = RC_ERROR;
  717.                                 Packet . Results[1] = ERROR_REQUIRED_ARG_MISSING;
  718.                             }
  719.                             else
  720.                             {
  721.                                 struct ExclusionInfo *Exclusion = ExclusionTable[CommandIndex];
  722.  
  723.                                     /* Any mutually-exclusive arguments? */
  724.  
  725.                                 if(Exclusion)
  726.                                 {
  727.                                     BYTE ArgsOkay = TRUE;
  728.  
  729.                                     i = 0;
  730.  
  731.                                         /* Look for arguments to
  732.                                          * exclude each other.
  733.                                          */
  734.  
  735.                                     while(ArgsOkay && Exclusion[i] . A != -1)
  736.                                     {
  737.                                         if(Array[Exclusion[i] . A] && Array[Exclusion[i] . B])
  738.                                             ArgsOkay = FALSE;
  739.                                         else
  740.                                             i++;
  741.                                     }
  742.  
  743.                                         /* All arguments correct? */
  744.  
  745.                                     if(ArgsOkay)
  746.                                         Processed = InvokeRexxCommand(&Packet);
  747.                                     else
  748.                                     {
  749.                                         Packet . Results[0] = RC_ERROR;
  750.                                         Packet . Results[1] = ERROR_TOO_MANY_ARGS;
  751.                                     }
  752.                                 }
  753.                                 else
  754.                                     Processed = InvokeRexxCommand(&Packet);
  755.                             }
  756.  
  757.                                 /* Free allocated parser data. */
  758.  
  759.                             if(!Processed)
  760.                                 FreeArgs(Args);
  761.                         }
  762.                         else
  763.                         {
  764.                             LONG Error = IoErr();
  765.  
  766.                             SetIoErr(Error);
  767.  
  768.                             Packet . Results[0] = RC_ERROR;
  769.                             Packet . Results[1] = IoErr();
  770.                         }
  771.  
  772.                             /* Free parser data. */
  773.  
  774.                         if(!Processed)
  775.                             FreeDosObject(DOS_RDARGS,Args);
  776.                     }
  777.                     else
  778.                     {
  779.                         Packet . Results[0] = RC_ERROR;
  780.                         Packet . Results[1] = ERROR_NO_FREE_STORE;
  781.                     }
  782.  
  783.                         /* Free temporary buffer. */
  784.  
  785.                     if(!Processed)
  786.                         FreeVecPooled(Array);
  787.                 }
  788.                 else
  789.                 {
  790.                     Packet . Results[0] = RC_ERROR;
  791.                     Packet . Results[1] = ERROR_NO_FREE_STORE;
  792.                 }
  793.             }
  794.             else
  795.             {
  796.                 Packet . Array    = NULL;
  797.                 Packet . Args    = NULL;
  798.  
  799.                 Processed = InvokeRexxCommand(&Packet);
  800.             }
  801.  
  802.             if(!Processed)
  803.             {
  804.                 if(Packet . Results[0] && Packet . Results[1])
  805.                     LastRexxError = Packet . Results[1];
  806.  
  807.                 ReplyRexxCommand(RexxMsg,Packet . Results[0],Packet . Results[1]);
  808.             }
  809.  
  810.             return(TRUE);
  811.         }
  812.     }
  813.  
  814.     return(FALSE);
  815. }
  816.  
  817.     /* RexxPktCleanup(struct RexxPkt *Packet,STRPTR Result):
  818.      *
  819.      *    Free the memory allocated for a message packet.
  820.      */
  821.  
  822. VOID __regargs
  823. RexxPktCleanup(struct RexxPkt *Packet,STRPTR Result)
  824. {
  825.     if(Packet -> Args)
  826.     {
  827.         FreeArgs(Packet -> Args);
  828.  
  829.         FreeDosObject(DOS_RDARGS,Packet -> Args);
  830.     }
  831.  
  832.     if(Packet -> Array)
  833.         FreeVecPooled(Packet -> Array);
  834.  
  835.     if(Packet -> Results[0])
  836.     {
  837.             /* Store error code. */
  838.  
  839.         if(Packet -> Results[1])
  840.         {
  841.             UBYTE Buffer[10];
  842.  
  843.             SPrintf(Buffer,"%ld",LastRexxError = Packet -> Results[1]);
  844.  
  845.             if(Packet -> RexxMsg)
  846.                 SetRexxVar(Packet -> RexxMsg,"TERM.LASTERROR",Buffer,strlen(Buffer));
  847.         }
  848.  
  849.         ReplyRexxCommand(Packet -> RexxMsg,Packet -> Results[0],Packet -> Results[1]);
  850.  
  851.         if(Result)
  852.             DeleteArgstring(Result);
  853.     }
  854.     else
  855.     {
  856.         if(Result)
  857.         {
  858.             if(Packet -> RexxMsg)
  859.             {
  860.                 if(Packet -> RexxMsg -> rm_Action & RXFF_RESULT)
  861.                     ReplyRexxCommand(Packet -> RexxMsg,0,(LONG)Result);
  862.                 else
  863.                 {
  864.                     DeleteArgstring(Result);
  865.  
  866.                     ReplyRexxCommand(Packet -> RexxMsg,0,0);
  867.                 }
  868.             }
  869.             else
  870.                 DeleteArgstring(Result);
  871.         }
  872.         else
  873.             ReplyRexxCommand(Packet -> RexxMsg,0,0);
  874.     }
  875. }
  876.  
  877.     /* RexxServer(VOID):
  878.      *
  879.      *    Asynchronous ARexx host server.
  880.      */
  881.  
  882. VOID __saveds
  883. RexxServer(VOID)
  884. {
  885.         /* Create the public host port. */
  886.  
  887.     if(RexxPort = CreateMsgPort())
  888.     {
  889.         struct RexxMsg    *RexxMsg;
  890.         ULONG         SignalSet;
  891.         BYTE         Done = FALSE;
  892.  
  893.         InitSemaphore(&RexxLaunchSemaphore);
  894.  
  895.         RexxPort -> mp_Node . ln_Name    = RexxPortName;
  896.         RexxPort -> mp_Node . ln_Pri    = 1;
  897.  
  898.             /* Make it a public port. */
  899.  
  900.         AddPort(RexxPort);
  901.  
  902.             /* Signal our father that we're running. */
  903.  
  904.         Signal(ThisProcess,SIG_HANDSHAKE);
  905.  
  906.             /* Go into loop and wait for input. */
  907.  
  908.         do
  909.         {
  910.             SignalSet = Wait(SIG_KILL | PORTMASK(RexxPort));
  911.  
  912.                 /* Are we to quit? */
  913.  
  914.             if(SignalSet & SIG_KILL)
  915.                 Done = TRUE;
  916.  
  917.                 /* This is probably a Rexx command. */
  918.  
  919.             if(SignalSet & PORTMASK(RexxPort))
  920.             {
  921.                     /* Pick up all the messages. */
  922.  
  923.                 while(RexxMsg = (struct RexxMsg *)GetMsg(RexxPort))
  924.                 {
  925.                         /* This is probably the reply to some
  926.                          * synchronous function invocation.
  927.                          */
  928.  
  929.                     if(RexxMsg -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG)
  930.                         FreeVecPooled(RexxMsg);
  931.                     else
  932.                     {
  933.                             /* At first try to run the
  934.                              * command asynchronously.
  935.                              * If this turns out to be
  936.                              * somewhat `impossible' pass
  937.                              * it to the `term' main process
  938.                              * or - if in batch mode - try
  939.                              * to deal with the message
  940.                              * on our own.
  941.                              */
  942.  
  943.                         if(!ParseRexxCommand(RexxMsg))
  944.                         {
  945.                             UBYTE Buffer[10];
  946.  
  947.                             SPrintf(Buffer,"%ld",LastRexxError = TERMERROR_UNKNOWN_COMMAND);
  948.  
  949.                             SetRexxVar(RexxMsg,"TERM.LASTERROR",Buffer,strlen(Buffer));
  950.  
  951.                             ReplyRexxCommand(RexxMsg,RC_ERROR,TERMERROR_UNKNOWN_COMMAND);
  952.                         }
  953.                     }
  954.                 }
  955.             }
  956.         }
  957.         while(!Done);
  958.  
  959.         Done = FALSE;
  960.  
  961.             /* Process remaining messages. */
  962.  
  963.         do
  964.         {
  965.             while(RexxMsg = (struct RexxMsg *)GetMsg(RexxPort))
  966.             {
  967.                 if(RexxMsg -> rm_Node . mn_Node . ln_Type == NT_REPLYMSG)
  968.                     FreeVecPooled(RexxMsg);
  969.                 else
  970.                     ReplyRexxCommand(RexxMsg,-1,0);
  971.             }
  972.  
  973.             ObtainSemaphore(&RexxLaunchSemaphore);
  974.  
  975.             if(!RexxLaunchCount)
  976.             {
  977.                 Done = TRUE;
  978.  
  979.                 ReleaseSemaphore(&RexxLaunchSemaphore);
  980.             }
  981.             else
  982.             {
  983.                 ReleaseSemaphore(&RexxLaunchSemaphore);
  984.  
  985.                 WaitPort(RexxPort);
  986.             }
  987.         }
  988.         while(!Done);
  989.  
  990.         DeleteMsgPort(RexxPort);
  991.  
  992.         RexxPort = NULL;
  993.     }
  994.  
  995.     Forbid();
  996.  
  997.     RexxProcess = NULL;
  998.  
  999.     Signal(ThisProcess,SIG_HANDSHAKE);
  1000. }
  1001.  
  1002.     /* HandleRexx():
  1003.      *
  1004.      *    Tiny & simple subroutine to read and examine all
  1005.      *    messages coming in to be processed synchronously
  1006.      *    by the `term' main process.
  1007.      */
  1008.  
  1009. BYTE
  1010. HandleRexx()
  1011. {
  1012.     struct RexxPkt *Packet;
  1013.  
  1014.         /* Obtain the message packet. */
  1015.  
  1016.     if(Packet = (struct RexxPkt *)GetMsg(TermRexxPort))
  1017.     {
  1018.         STRPTR Result;
  1019.  
  1020.         InRexx = TRUE;
  1021.  
  1022.         UpdateRequired = TransferUpdateRequired = FALSE;
  1023.  
  1024.             /* Execute the command. */
  1025.  
  1026.         Result = (*Packet -> CommandInfo -> Routine)(Packet);
  1027.  
  1028.             /* Free the packet data. */
  1029.  
  1030.         RexxPktCleanup(Packet,Result);
  1031.  
  1032.             /* Update the configuration if necessary. */
  1033.  
  1034.         if(UpdateRequired)
  1035.             ConfigSetup();
  1036.  
  1037.             /* Update the XPR options if necessary. */
  1038.  
  1039.         if(TransferUpdateRequired)
  1040.         {
  1041.             if(ProtocolSetup(TRUE))
  1042.                 SaveProtocolOpts();
  1043.         }
  1044.  
  1045.             /* Return the message packet. */
  1046.  
  1047.         ReplyMsg((struct Message *)Packet);
  1048.  
  1049.         InRexx = FALSE;
  1050.  
  1051.         return(TRUE);
  1052.     }
  1053.     else
  1054.         return(FALSE);
  1055. }
  1056.